/*******************************************************************************

  Pilot Intelligence Library
    http://www.pilotintelligence.com/

  ----------------------------------------------------------------------------

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.

*******************************************************************************/

#ifndef __NETTRANSFER_UDP_H__
#define __NETTRANSFER_UDP_H__

#include "base/Svar/DataStream.h"
#include "base/osa/osa++.h"
#include "Socket++.h"

namespace pi {

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////


///
/// \brief The simple data transfer class which uses UDP.
///     server - recv data
///     client - send data
///
///     This class provide a way to transfer data with reliable manner. So you don't
///         worry about the disorder of the received data. But it do not support
///         data missing (resend data).
///
class NetTransfer_UDP : public Thread
{
public:
    NetTransfer_UDP();
    virtual ~NetTransfer_UDP();

    ///
    /// \brief open the UDP transfer - for simple transmitting message
    ///
    /// \param isServer     - 0: client, sedning message
    ///                       1: server, receiving message
    /// \param port         - port number (default 30000)
    /// \param addr         - remote address (for client) or multicast address
    /// \param st           - socket type
    ///                         SOCKET_UDP              - normal UDP
    ///                         SOCKET_UPD_MULTICAST    - multicast UDP
    ///
    /// \return
    ///         0           - success
    ///         other       - failed
    ///
    virtual int open(int isServer=1,
                     int port=30000, const std::string &addr="225.0.0.10",
                     RSocketType st=SOCKET_UDP_MULTICAST);

    ///
    /// \brief close the UDP transfer
    ///
    /// \return
    ///
    virtual int close(void);

    ///
    /// \brief send data to remote terminal
    ///
    /// \param dat          - message buffer
    /// \param len          - message length
    ///
    /// \return
    ///     if success return sended message length
    ///     -1              - failed (maybe UDP not opened)
    ///
    virtual int send(uint8_t *dat, int len);

    ///
    /// \brief send data to remote terminal
    ///
    /// \param ds           - datastream
    ///
    /// \return
    ///     if success return sended message length
    ///     -1              - failed (maybe UDP not opened)
    ///
    virtual int send(RDataStream &ds);


    ///
    /// \brief recved message processing function
    ///
    /// \param dat          - message buffer
    /// \param len          - message length
    ///
    /// \return
    ///     if success return sended message length
    ///     -1              - failed (maybe UDP not opened)
    ///
    virtual int recv(uint8_t *dat, int len);

    ///
    /// \brief recved message processing function
    ///
    /// \param ds           - datastream
    ///
    /// \return
    ///     if success return sended message length
    ///     -1              - failed (maybe UDP not opened)
    ///
    virtual int recv(RDataStream &ds);

    ///
    /// \brief recved message slot function
    ///
    /// \param dat          - message buffer
    /// \param len          - message length
    ///
    /// \return
    ///     0               - success
    ///
    virtual int recvSlot(uint8_t *dat, int len);


    ///
    /// \brief return connection is established or not
    ///
    /// \return
    ///     1               - connected
    ///     0               - not connected
    ///
    int isOpened(void) { return m_isConnected; }

    ///
    /// \brief set Transfer maximum BPS
    ///
    /// \param kBPS         - maximum sending kBPS
    ///
    /// \return
    ///
    int setTransferBPS(int kBPS) { m_transferBPS = kBPS; }

    ///
    /// \brief getTransferBPS
    ///
    /// \return
    ///     the maximum sending kBPS
    ///
    int getTransferBPS(void) { return m_transferBPS; }

    ///
    /// \brief setCheckMode
    /// \param _mode  - 0: Parity-Check
    ///               - 1: Cyclic Redundancy Check(CRC)
    ///               - 2: md5 check
    /// \return
    ///         m_checkmode
    ///
    int setCheckMode(int _mode) { m_checkMode = _mode;}
    int getCheckMode(void)  { return m_checkMode; }

    ///
    /// \brief get Dequesize of sending thread
    /// \return
    ///
    int getQueueSize(void);


public:
    ///
    /// \brief thread_func - receiving/sending thread
    ///
    /// \param arg          - thread argument
    ///
    /// \return
    ///
    virtual void threadFunc();
    void threadFunc_recv();
    void threadFunc_send();

protected:
    RSocketType     m_socketType;                   ///< socket type;
    RSocket         m_socket;                       ///< socket obj
    int             m_isServer;                     ///< 0-client(TX), 1-server(RX)
    int             m_isConnected;                  ///< connected or not

    std::string     m_addr;                         ///< remote terminal address
    int             m_port;                         ///< UDP port

    uint64_t        m_msgID;                        ///< message ID

    int             m_transferBPS;                  ///< transfer data maximum byte-per-seconds
                                                    ///<    the unit is kBPS (1000 bytes/second)
    int             m_checkMode;                    ///< method for data checksum
    Mutex           m_mutexSend;                    ///< mutex for message counting

protected:
    class NetTransfer_PacketPool;
    SPtr<NetTransfer_PacketPool>    m_packPool;     ///< inner used package pool
};

} // end of namespace pi

#endif // end of __NETTRANSFER_UDP_H__

